<script setup lang="ts" xmlns="http://www.w3.org/1999/html">
import {inject, reactive, ref, watch} from "vue";
import {ElNotification, UploadProps, UploadUserFile} from "element-plus";
import {uploadUrl, uploadFile, backUploadFile, mergeFileId, checkFileIntegrity} from "@/api/upload/upload.ts"
import {debounce} from 'lodash';
import {getToken} from "@/utils/auth.ts";
import {createHashFile, createHashFileId} from "@/utils/HashFixedSalt.ts";
import {Check} from "@element-plus/icons-vue";
import Loading from "@/components/particle/loading.vue";

const headers = {'Authorization': getToken()};
const fileList = ref<UploadUserFile[]>([])
const chunkSize: number = 4 * 1024 * 1024; // 默认分片大小4MB
const reload: any = inject('reload');
const percentage = reactive({
  loading: false,
  centerDialogVisible: false,
  percentage: '',
  title: "",
  count: 0
})


watch(() => percentage.percentage, (newValue:any) => {
  if (newValue === '100.00') {
    debouncedNotify()
    emits('uploadSuccess')
    setTimeout(() => {
      percentage.centerDialogVisible = false
      percentage.title = "文件上传成功"
      reload();
    }, 1000)
  }
})

const emits = defineEmits(['uploadSuccess']);
const props = defineProps({
  pid: {
    type: String,
    required: true
  }
})

interface MergeFile {
  fileId: string
  hash: any
  name: string,
  pid: string,
  size: any,
  type: number,
}

// 文件完整性校验
const chuckedFile = async (data: any) => {
  let result: any = null
  await checkFileIntegrity(data).then((res: any) => {
    result = res.data
  })
  return result
}


// 文件流转SHA256
const readFile = (file: any) => {
  return new Promise(resolve => {
    const reader = new FileReader();
    reader.onload = (e: any) => {
      const bytes = e.target.result
      const hash = createHashFile(bytes).hashedFile
      resolve(hash.toString())
      percentage.title = `文件切片完成，文件上传中...`
      percentage.loading = true
    }
    reader.readAsArrayBuffer(file)
  })
}


// 文件加密值读取
const readFileSHA256 = (chunk: any[]) => {
  const chunkCount = chunk.length
  return new Promise(resolve => {
    const result: any[] = []
    const _reader = (i: number) => {
      if (i >= chunk.length) {
        return resolve(result) // 读取完成
      }
      let fileSlice = chunk[i]
      let reader = new FileReader();

      reader.onload = (e: any) => {
        const bytes = e.target.result
        const hash = createHashFile(bytes).hashedFile
        result.push({'fileNum': i, 'fileSHA256': hash.toString(), 'file': fileSlice, chunkCount})
        _reader(i + 1)
      }
      reader.readAsArrayBuffer(fileSlice)
    }
    _reader(0)
  })
}

// 使用 debounce 函数创建防抖通知函数
const debouncedNotify = debounce(() => {
  ElNotification({
    title: '文件上传成功',
    type: 'success',
    showClose: false,
  });
}, 200); // 设置防抖延迟
const successCount = ref(0)
// 文件上传封装
const manualUpload = (file: any, data: any) => {
  uploadFile(file, data).then(res => {
    if (res.data.code === 200) {
      successCount.value += 1
      percentage.percentage = Number((successCount.value / data.count) * 100).toFixed(2)
    }
    if (res.data.code === 500) {
      ElNotification({
        title: res.data.msg,
        type: 'error',
        showClose: false,
      });
    }

  })
}

// 断点续传上传封装
const backManualUpload = (file: any, data: any, sumHash: any, count: any) => {
  backUploadFile(file, data, sumHash).then(res => {
    if (res.data.code === 200) {
      successCount.value += 1
      percentage.percentage = Number((successCount.value / count) * 100).toFixed(2)
    } else {
      ElNotification({
        title: res.data.msg,
        type: 'error',
        showClose: false,
      });
    }
  })
}

//文件切片函数
const spliceFile = (file: any, chunkSize: number) => {
  percentage.count = Math.ceil(file.size / chunkSize)
  percentage.title = `文件切片开始，总块数${percentage.count}`
  percentage.loading = false

  const result = []
  for (let i = 0; i < file.size; i += chunkSize) {
    const fileSlice = file.slice(i, i + chunkSize)
    result.push(fileSlice)
  }
  return result;
}

const handleChange: UploadProps['onChange'] = async (uploadFile) => {
  percentage.centerDialogVisible = true
  const fileList = spliceFile(uploadFile.raw, chunkSize)
  let sumFileHash = await readFile(uploadFile.raw);
  const fileId = await createHashFileId(uploadFile.uid).hashedFileId;
  let pid = ''
  let merge: MergeFile = {
    fileId: fileId,
    hash: sumFileHash,
    name: uploadFile.name,
    pid: props.pid,
    size: uploadFile.size,
    type: 0
  }

  try {
    const res = await chuckedFile(merge);
    const chuckFile: any = [];
    const code = res.code;
    const mergeRes = await mergeFileId(merge);
    pid = mergeRes.data.data;

    const fileRes: any = await readFileSHA256(fileList);
    fileRes.forEach((e: any) => {
      let obj: any = {}; // 创建普通对象
      obj['hash'] = e.fileSHA256; // 设置属性
      obj['count'] = e.chunkCount;
      obj['fileId'] = fileId;
      obj['file'] = e.file;
      obj['num'] = e.fileNum;
      obj['pid'] = pid;
      obj['size'] = e.file.size;
      chuckFile.push(obj);
    });

    if (code === 211) {
      chuckFile.forEach((e: any) => {
        const {file, ...rest} = e;
        manualUpload(e.file, rest)
      })
    } else if (code === 212) {
      ElNotification({
        title: '当前文件已完整上传',
        type: 'success',
        showClose: false,
      });
      percentage.centerDialogVisible = false
    } else if (code === 213) {
      ElNotification({
        title: '断点续传执行',
        type: 'success',
        showClose: false,
      });
      const resFile = res.data
      // 移除数组 fileRes 中所有与数组 resFile 中元素 hash 相同的元素
      const filteredFileRes = chuckFile.filter((fileLocal: any) =>
          !resFile.some((fileService: any) =>
              fileLocal.hash === fileService.hash
          ));
      percentage.count = filteredFileRes.length;
      filteredFileRes.forEach((a: any) => {
        const {file, ...rest} = a;
        backManualUpload(a.file, rest, sumFileHash, filteredFileRes.length)
      })

    } else if (code === 214) {
      ElNotification({
        title: '文件上传成功（秒传）',
        type: 'success',
        showClose: false,
      });
      emits('uploadSuccess')
      percentage.centerDialogVisible = false
    }
  } catch (error) {
    console.error("处理错误:", error);
  }


}
</script>
<template>
  <el-upload
      v-model:file-list="fileList"
      ref="uploadRef"
      drag
      :headers="headers"
      :action="uploadUrl"
      :auto-upload="false"
      :on-change="handleChange"
      :show-file-list="false"
  >
    <slot></slot>
  </el-upload>
  <el-dialog
      v-model="percentage.centerDialogVisible"
      :show-close="false"
      width="500"
      align-center
  >
    <template #title>
      {{ percentage.title }}
    </template>
    <div>
      <loading v-show="!percentage.loading"/>
    </div>

    <el-progress type="circle" v-show="percentage.loading" status="success" :percentage="percentage.percentage">
      <span
          v-show="Number(successCount) !== Number(percentage.count)">{{
          percentage.percentage + '%'
        }}<br/>{{ successCount + '/' + percentage.count }}</span>
      <el-button type="success" :icon="Check" circle v-show="Number(successCount) === Number(percentage.count)"/>
    </el-progress>
  </el-dialog>

</template>
<style lang="scss" scoped>

</style>
